<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 * @author   howe <howe1995@163.com>
 */

namespace App\Controller;

use App\Cache\SocketRoom;
use App\Constant\TalkEventConstant;
use App\Event\TalkEvent;
use App\Repository\GroupUserRepository;
use App\Services\SocketClientService;
use Hyperf\Contract\OnCloseInterface;
use Hyperf\Contract\OnMessageInterface;
use Hyperf\Contract\OnOpenInterface;
use Hyperf\Di\Annotation\Inject;

class WebSocketController extends AbstractController implements OnMessageInterface, OnOpenInterface, OnCloseInterface
{
    #[Inject]
    protected SocketClientService $client;

    /**
     * Note - websocket 消息回调
     * DateTime 2024/12/20 17:05
     * User Admin.
     * @param mixed $server
     * @param mixed $frame
     */
    public function onMessage($server, $frame): void
    {
        $result = json_decode($frame->data, true);
        // 判断是否为心跳检测
        if ($result['action'] == 'heartbeat') {
            $server->push($frame->fd, json_encode(['who' => TalkEventConstant::WHO_MESSAGE, 'action' => 'heartbeat', 'data' => ['type' => 'pong', 'time' => date('Y-m-d H:i:s')]]));
        }
        // return;
    }

    /**
     * Note - websocket 连接关闭回调
     * DateTime 2024/12/20 17:01
     * User Admin.
     * @param mixed $server
     */
    public function onClose($server, int $fd, int $reactorId): void
    {
        $user_id = $this->client->findFdUserId($fd);
        stdout_log()->notice("客户端FD:{$fd} 已关闭连接 ，用户ID为【{$user_id}】，关闭时间：" . date('Y-m-d H:i:s'));
        // 删除 fd 绑定关系
        $this->client->unbind($fd);
        // 判断是否存在异地登录
        $isOnline = $this->client->isOnlineAll($user_id);
        if ($isOnline) {
            return;
        }
        event()->dispatch(new TalkEvent([
            'who' => TalkEventConstant::WHO_USER,
            'action' => TalkEventConstant::ACTION_LOGOUT,
            'data' => [
                'from' => $user_id,
                'message' => '用户下线',
                'status' => 0,
            ],
        ]));
    }

    /**
     * Note - websocket 连接成功回调
     * DateTime 2024/12/20 16:31
     * User Admin.
     * @param mixed $server
     * @param mixed $request
     */
    public function onOpen($server, $request): void
    {
        // 当前连接的用户
        $user_id = auth()->user()->getId();
        stdout_log()->notice("用户连接信息 : user_id:{$user_id} | fd:{$request->fd} 时间：" . date('Y-m-d H:i:s'));
        // 绑定fd与用户关系
        $this->client->bind($request->fd, $user_id);
        $groupIds = GroupUserRepository::getUserGroupIds($user_id);
        foreach ($groupIds as $group_id) {
            SocketRoom::getInstance()->addRoomMember(strval($group_id), strval($user_id));
        }

        // 判断是否存在异地登录
        $isOnline = $this->client->isOnlineAll($user_id);
        if ($isOnline) {
            event()->dispatch(new TalkEvent([
                'who' => TalkEventConstant::WHO_USER,
                'action' => TalkEventConstant::ACTION_LOGIN,
                'data' => [
                    'from' => $user_id,
                    'message' => '用户上线',
                    'status' => 0,
                ],
            ]));
        }
    }
}
